#ifndef __HEADER__
#define __HEADER__
#include "../common.h"
#include <linux/fs.h>
#include <linux/spinlock.h>
#include <linux/blkdev.h>
#include <net/sock.h>
#define STR_EQUAL(S,P) strcmp(S,P)==0
#define camera_path_head ag->camera_path_head
#define camera_path_tail ag->camera_path_tail
#define exclude_path_head ag->exclude_path_head
#define exclude_path_tail ag->exclude_path_tail
#define mount_to ag->mount_to
#define filter_head ag->filter_head
#define filter_tail ag->filter_tail
#define block_size ag->block_size
#define FSNAME(i) i->i_sb->s_type->name
#define IS_EXT3(nm) (!strcmp(nm, "ext3"))
#define IS_EXT4(nm) (!strcmp(nm, "ext4"))
#define FOR(I,S,T) for(I=S;I<T;I++)

typedef struct file_node {
	struct dentry* dentry;
	struct file_node* parent;
	struct file_node* nextSib;
	struct file_node* firstChd;
} file_node;

void cat_abs_path(char*, file_node*);
#define PA(n) n->parent
#define LC(n) n->firstChd
#define RC(n) n->nextSib

file_node* get_next_node(file_node*);
extern struct sock* __server_sock;

int  start_listen(void);
void stop_listen(void);
void release_camera_tree(file_node*);
void print_camera_tree(file_node*, int);
file_node* build_cow_tree(args*, void*);
int calc_tree_size(file_node*);
extern get_block_t* ext4_get_block_fn;

#define release_tree ReleaseTree
#define insert_key InsertKey
#define remove_key RemoveKey
#define query_key QueryKey
#define release_sbt ReleaseTree
#define get_first_key GetFirstKey
typedef void (*ReleaseKeyFn)(void*);
typedef void (*PrintKeyFn)(void*);
typedef int (*CompareKeyFn)(void*, void*);
typedef void (*CopyKeyFn)(void*, void*);

typedef struct SelBalanceTree {
	void* root;
	spinlock_t lock;
	ReleaseKeyFn release_key_fn;
	CompareKeyFn is_equal;
	CompareKeyFn is_smaller;
	CompareKeyFn is_bigger;
	CopyKeyFn copy;
	PrintKeyFn print_fn;
} SelBalanceTree, self_balance_tree;

typedef self_balance_tree* sbt;

typedef struct args_queue_elem
{
	args* ag;
	size_t seq;
	size_t all, done;
	file_node* root;
	spinlock_t lock;
	sbt sbt_from, sbt_to;
	atomic_t should_freeze;
	wait_queue_head_t frez_cond;
	struct args_queue_elem *next;
} args_queue_elem; 

typedef struct mk_fn_node
{
	void* key;
	make_request_fn* fn;
	struct mk_fn_node* next;
} mk_fn_node;

extern spinlock_t mk_fn_lock;
extern mk_fn_node* mk_fn_head;
void* lookup_fn(void*);
void append_fn(void*, make_request_fn*);
void clean_fn(void);
void clean_args_queue(void);

void replace_make_request(struct super_block*, args_queue_elem*);
void restore_make_request(struct super_block*);

sbt alloc_sbt(void);
void record_blocks(void*, void*, sbt, sbt);
void copy_blocks(args_queue_elem*);

void* GetFirstKey(SelBalanceTree*);
void InsertKey(SelBalanceTree*, void*);
void* QueryKey(SelBalanceTree*, void*);
void RemoveKey(SelBalanceTree*, void*);
void ReleaseTree(SelBalanceTree*);
void PrintTree(SelBalanceTree*);

void* get_std_file(void);
void* get_log_file(void);
typedef void* (*get_file_fn_t)(void);
int read_test_code(void);
int atoi(const char*);
void print_kernel(get_file_fn_t, int, const char* fmt, ...);
/*
  void print_std_kernel(const char*,...);
  void print_log_kernel(const char*,...);
*/
#endif
